import * as THREE from "three"
import Ne from "../packages/76870"
import se from "../math/69626"
import { DragEndEvent, DragEvent } from "../event/DragEvent"
import cursorEnum from "../enum/cursor.enum"
import measuringPhaseEnum from "../enum/measuringPhase.enum"
import Comparator from "../utils/Comparator"
import { ClickEvent, HoverEvent, UnhoverEvent } from "../event/GestureEvent"
const isOK = e => (e instanceof ClickEvent ? e.button === Ne.MP.PRIMARY : e.buttons === Ne.r3.PRIMARY)
export default class MeasurementInput extends THREE.Mesh {
  pointGroups: any
  input: any
  cameraData: any
  mobile: any
  changeCursor: any
  getPhase: any
  changePhase: any
  restorePreviousPhase: any
  setSelectedLine: any
  getSelected: any
  onDragStart: any
  onDragEnd: any
  inputSubscriptions: any[]
  groupVisible: any[]
  editingGroup: any
  editingPointIndex: any
  constructor(
    pointGroups,
    input,
    cameraData,
    mobile,
    changeCursor,
    getPhase,
    changePhase,
    restorePreviousPhase,
    setSelectedLine,
    getSelected,
    onDragStart,
    onDragEnd
  ) {
    super()
    this.pointGroups = pointGroups
    this.input = input
    this.cameraData = cameraData
    this.mobile = mobile
    this.changeCursor = changeCursor
    this.getPhase = getPhase
    this.changePhase = changePhase
    this.restorePreviousPhase = restorePreviousPhase
    this.setSelectedLine = setSelectedLine
    this.getSelected = getSelected
    this.onDragStart = onDragStart
    this.onDragEnd = onDragEnd
    this.inputSubscriptions = []
    this.groupVisible = []
    this.raycast = (() => {
      const e = new THREE.Vector3()
      return (t, i) => {
        const { pose, width } = this.cameraData
        const r = 0.005 * width
        const o = pose.projection.asThreeMatrix4()
        const a = pose.position
        let h,
          l = 0,
          d = 0
        if (this.getPhase() === measuringPhaseEnum.IDLE || this.getPhase() === measuringPhaseEnum.EDITING) {
          for (let i = 0; i < this.pointGroups.groupCount; ++i) {
            const s = this.pointGroups.getGroup(i)
            if (!(void 0 !== this.editingGroup && this.editingGroup !== i) && this.groupVisible[i]) {
              for (let c = 0; c < s.count - 1; ++c) {
                const u = s.get(c),
                  p = s.get(c + 1)
                if (u && p) {
                  const s = t.ray.distanceSqToSegment(u, p, void 0, e),
                    c = a.distanceTo(e)
                  let g = se._U(c, o, width) * r
                  if (((g *= g), s < g)) {
                    let n,
                      r = e
                    this.editingPointIndex
                      ? (n = this.editingPointIndex)
                      : u.distanceToSquared(e) < 2 * g
                      ? ((n = d), (r = u))
                      : p.distanceToSquared(e) < 2 * g && ((n = d + 1), (r = p)),
                      (!h || s < l) &&
                        ((h = {
                          distance: t.ray.origin.distanceTo(r),
                          point: r,
                          object: this,
                          instanceId: i,
                          index: n
                        }),
                        (l = s))
                  }
                }
                d++
              }
              d++
            } else d += s.count
          }
        }

        h && i.push(h)
      }
    })()
    this.inputSubscriptions.push(...this.registerCommonInput())
    mobile || this.inputSubscriptions.push(...this.registerHoverInput())
    this.deactivate()
  }
  activate() {
    this.input.registerMesh(this, !1), this.inputSubscriptions.forEach(e => e.renew())
  }
  deactivate() {
    this.input.unregisterMesh(this), this.inputSubscriptions.forEach(e => e.cancel())
  }
  dispose() {
    this.deactivate()
  }
  setEditingGroup(e) {
    this.editingGroup = e
  }
  setGroupVisible(e, t) {
    this.groupVisible[e] = t
  }
  validJoint(e) {
    return !!e && void 0 !== e.index
  }
  registerHoverInput() {
    return [
      this.input.registerMeshHandler(HoverEvent, Comparator.isType(MeasurementInput), (_e, _t, i) => {
        this.getPhase() === measuringPhaseEnum.IDLE && this.changeCursor(i && void 0 !== i.index ? cursorEnum.GRAB : cursorEnum.FINGER)
      }),
      this.input.registerMeshHandler(UnhoverEvent, Comparator.isType(MeasurementInput), () => {
        this.getPhase() === measuringPhaseEnum.IDLE && this.changeCursor(cursorEnum.DEFAULT)
      })
    ]
  }
  registerCommonInput() {
    return [
      this.input.registerMeshHandler(ClickEvent, Comparator.isType(MeasurementInput), (e, _t, i) => {
        if (!isOK(e)) return !1
        if (this.getPhase() !== measuringPhaseEnum.IDLE) return !1
        const s = i && void 0 !== i.instanceId ? i.instanceId : -1,
          n = this.getSelected() === s ? -1 : s
        return this.setSelectedLine(n), !0
      }),
      this.input.registerMeshHandler(
        DragEvent,
        Comparator.isType(MeasurementInput),
        (e, _t, i) =>
          !!isOK(e) &&
          (!this.validJoint(i) ||
            !i ||
            void 0 === i.instanceId ||
            (this.getPhase() === measuringPhaseEnum.EDITING ||
              ((this.editingPointIndex = i.index),
              this.onDragStart(i.instanceId),
              this.setSelectedLine(i.instanceId),
              this.changePhase(measuringPhaseEnum.EDITING),
              this.mobile || this.changeCursor(cursorEnum.GRABBING)),
            !0))
      ),
      this.input.registerMeshHandler(
        DragEndEvent,
        Comparator.isType(MeasurementInput),
        () =>
          this.getPhase() === measuringPhaseEnum.EDITING &&
          ((this.editingPointIndex = void 0), this.restorePreviousPhase(), this.onDragEnd(), this.mobile || this.changeCursor(cursorEnum.DEFAULT), !0)
      )
    ]
  }
}
